package org.belkodevelop.controller.helper;

import java.util.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.belkodevelop.security.SimpleAuthenticationToken;
import org.belkodevelop.user.domain.User;
import org.belkodevelop.user.exception.UserNotFoundException;
import org.belkodevelop.user.service.UserService;
import org.belkodevelop.userdatails.UserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.stereotype.Component;

@Component
public class AuthUtils {
    
    private final Log log = LogFactory.getLog(getClass()); 

    @Autowired
    @Qualifier("authenticationManager")
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private RememberMeServices rememberMeServices; 
    
    @Autowired
    private UserService userService;
    
    private static class RememberMeRequestWrapper extends HttpServletRequestWrapper {
        
        private Map parameters;
        
        public RememberMeRequestWrapper(HttpServletRequest request, boolean rememberMe) {
            super((HttpServletRequest)request);
            parameters = new HashMap();
            if (rememberMe) {
                parameters.put("_spring_security_remember_me", "true");
            }
        }

        @Override
        public String getParameter(String paramName) {
            return (parameters.get(paramName) != null ? 
                    parameters.get(paramName).toString() : 
                    null);
        }

        @Override
        public String[] getParameterValues(String paramName) {
            return (String[]) parameters.values().toArray();
        }
        
        @Override
        public Enumeration getParameterNames() {
            return Collections.enumeration(parameters.keySet());
        }
        
        @Override
        public Map getParameterMap() {
            return parameters;
        }
       
    }
    
    public Authentication login(String login,
                         String password, 
                         boolean rememberMe, 
                         HttpServletRequest request, 
                         HttpServletResponse response) throws AuthenticationException {  
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(login, password);
        User details = new User();
        details.setLogin(login);
        token.setDetails(details);
        
        Authentication auth = authenticationManager.authenticate(token);

        if (auth.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(auth);
            rememberMeServices.loginSuccess(new RememberMeRequestWrapper((HttpServletRequest) request, rememberMe), response, auth);
            return auth;
        }
        return null;
    }
    
    public boolean forceLogin(String login) {
        UserDetails userAdapter;
        try {
            userAdapter = new UserDetails(userService.getUserByLogin(login));
        } catch (UserNotFoundException ex) {
            log.warn(null, ex);
            return false;
        }
        SimpleAuthenticationToken authToken = new SimpleAuthenticationToken("notAuthProvider", userAdapter);
        Authentication auth = authenticationManager.authenticate(authToken);
        if (auth.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(authToken); 
            return true;
        }
        return false;
    }
    
    /**
     * Экземпляр пользователя из сессии
     * @return 
     */
    public User getCurrentSessionUser() {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal instanceof UserDetails) {
            return ((UserDetails)principal).getUser();
        }
        return null;
    }
    
    /**
     * Экземпляр пользователя из базыданных
     * @return 
     */
    public User getCurrentUser() {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal instanceof UserDetails) {
            try {
                return userService.getUserById(((UserDetails)principal).getId());
            } catch (UserNotFoundException ex) {
                log.warn("Uncorrect user in session", ex);
            }
        }
        return null;
    }    
}
